package com.lau.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.MD5;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lau.entity.TSysFile;
import com.lau.mapper.TSysFileMapper;
import com.lau.service.ITSysFileService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;

import static com.lau.constant.SysConstant.MESSAGE;
import static com.lau.constant.SysConstant.SUCCESS;


/**
 * <p>
 * 系统文件列表 服务实现类
 * </p>
 *
 * @author Lau
 * @since 2024-06-07
 */
@Service
@Slf4j
public class TSysFileServiceImpl extends ServiceImpl<TSysFileMapper, TSysFile> implements ITSysFileService {
    private static final int BUFFER_LEN = 1024 * 1024 * 1;
    /**
     * 限制上传文件后缀
     */
    @Value("${file.service.suffixes}")
    private String fileSuffixes;
    @Value("${file.service.filesize}")
    private Long maxFileSize;
    // 文件上传目录
    @Value("${file.service.repository}")
    private String fileRepository;

    @Autowired
    TSysFileMapper fileMapper;

    @Override
    public JSONObject upload(MultipartFile file) {

        String fileName = file.getOriginalFilename();
        if (StrUtil.isBlank(fileName)) {
            return uploadFailed("文件名为空");
        }
        //文件后缀
        String fileExt = FilenameUtils.getExtension(fileName);
        List<String> fileSuffixList = Arrays.asList(fileSuffixes.split(","));
        if (!fileSuffixList.contains(fileExt) || !fileName.contains(".")) {
            return uploadFailed("文件后缀名仅限：" + fileSuffixes);
        }
        //文件大小判断
        if (file.getSize() > maxFileSize) {
            return uploadFailed("文件大小超出最大值：" + maxFileSize + " bytes");
        }

        try {
            //获取上传文件md5值
            String fileFingerPrint = MD5.create().digestHex16(file.getInputStream());
            //文件保存路径
            String uploadBasePath = FilenameUtils.concat(fileRepository, fileFingerPrint.substring(0, 6));
            File saveDir = new File(uploadBasePath);
            File saveFile = new File(saveDir, fileFingerPrint+"."+fileExt);
            if (!saveDir.exists()) {
                saveDir.mkdirs();
            }
            FileUtil.writeFromStream(file.getInputStream(), saveFile);
            String path = saveFile.getAbsolutePath();

            // 保存数据入库
            TSysFile sf = new TSysFile();
            sf.setFileFingerPrint(fileFingerPrint);
            sf.setFileName(fileName);
            sf.setFilePath(path);
            sf.setUpdateTime(LocalDateTime.now());
            sf.setCreateTime(LocalDateTime.now());
            sf.setStatusCode("0");
            sf.setFileExtension(fileExt);
            sf.setFileLen(file.getSize());
            String fileID = IdUtil.fastSimpleUUID();
            sf.setFileID(fileID);
            fileMapper.insert(sf);
            JSONObject json = new JSONObject();
            json.put(SUCCESS, true);
            json.put(MESSAGE, sf);
            return json;
        } catch (Exception e) {
            log.error("文件保存出错{}", e.getMessage());
            return uploadFailed("服务器500");
        }

    }

    public JSONObject upload2(MultipartFile file) {

        String fileName = file.getOriginalFilename();
        if (StrUtil.isBlank(fileName)) {
            return uploadFailed("文件名为空");
        }
        //文件后缀
        String fileExt = FilenameUtils.getExtension(fileName);
        List<String> fileSuffixList = Arrays.asList(fileSuffixes.split(","));
        if (!fileSuffixList.contains(fileExt) || !fileName.contains(".")) {
            return uploadFailed("文件后缀名仅限：" + fileSuffixes);
        }
        //文件大小判断
        if (file.getSize() > maxFileSize) {
            return uploadFailed("文件大小超出最大值：" + maxFileSize + " bytes");
        }

        //将上传的文件先写入临时文件
        String tempDirPath = fileRepository;
        String tempFileName = UUID.randomUUID().toString() + "_tmp";
        File tmpDir = new File(tempDirPath);
        File tmpFile = new File(tempDirPath, tempFileName);
        if (!tmpDir.exists()) {
            tmpDir.mkdirs();
        }

        try {
            RandomAccessFile accessTmpFile = new RandomAccessFile(tmpFile, "rw");
            writeStreamToFile(accessTmpFile, file);
            String s1 = MD5.create().digestHex16(file.getInputStream());
            String s = MD5.create().digestHex16(tempDirPath);
            //获取临时文件md5值
            String fileFingerPrint = getMd5ByFile(tmpFile);
            String uploadRootPath = FilenameUtils.getFullPath(tmpFile.getAbsolutePath());
            String uploadBasePath = FilenameUtils.concat(uploadRootPath, fileFingerPrint.substring(0, 6));
            String saveFileName = fileFingerPrint + "." + fileExt;
            String filePathStr = FilenameUtils.concat(uploadBasePath, saveFileName);

            File saveDir = new File(uploadBasePath);
            File saveFile = new File(saveDir, saveFileName);
            if (!saveDir.exists()) {
                saveDir.mkdirs();
            }
            Path filePath = FileUtils.getFile(filePathStr).toPath();
            if (Files.exists(filePath)) {
                Files.deleteIfExists(filePath);
            }
            FileUtil.move(tmpFile, saveFile, true);
            // 保存数据入库
            TSysFile sf = new TSysFile();
            sf.setFileFingerPrint(fileFingerPrint);
            sf.setFileName(fileName);
            String path = filePath.toString().substring(filePath.toString().indexOf(":") + 1).replaceAll("\\\\", "/");
            sf.setFilePath(path);
            sf.setUpdateTime(LocalDateTime.now());
            sf.setCreateTime(LocalDateTime.now());
            sf.setStatusCode("0");
            sf.setFileExtension(fileExt);
            sf.setFileLen(tmpFile.length());
            String fileID = IdUtil.fastSimpleUUID();
            sf.setFileID(fileID);
            fileMapper.insert(sf);
            JSONObject json = new JSONObject();
            json.put(SUCCESS, true);
            json.put(MESSAGE, sf);
            return json;
        } catch (Exception e) {
            log.error("文件保存出错{}", e.getMessage());
            return uploadFailed("服务器500");
        }

    }


    private JSONObject uploadFailed(String message) {
        JSONObject json = new JSONObject();
        json.put(SUCCESS, false);
        json.put(MESSAGE, message);
        return json;
    }

    private void writeStreamToFile(RandomAccessFile accessTmpFile, MultipartFile file) {
        InputStream content = null;
        try {
            // 定位到该分片的偏移量
            accessTmpFile.seek(0);
            // 写入该分片数据
            int read = 0;
            final byte[] bytes = new byte[BUFFER_LEN];
            content = file.getInputStream();
            while ((read = content.read(bytes)) != -1) {
                accessTmpFile.write(bytes, 0, read);
            }
        } catch (Exception e) {
            log.error("写入临时文件{}时error：{}", file.getOriginalFilename(), e.getMessage());
        } finally {
            if (content != null) {
                try {
                    content.close();
                    accessTmpFile.close();
                } catch (IOException e) {
                    log.error("写入临时文件{}关闭流时error：{}", file.getOriginalFilename(), e.getMessage());
                }
            }
        }
    }


    public String getMd5ByFile(File file) throws IOException {
        FileInputStream fis = new FileInputStream(file);
        String md5 = DigestUtils.md5Hex(IOUtils.toByteArray(fis));
        IOUtils.closeQuietly(fis);
        return md5;
    }
}
